#include "StdAfx.h"
#include "Service.h"
#include <windows.h>
#include <winsvc.h>
#include "ntservmsg.h"
#include "string.h"
#include "TestSMailer.h"


SERVICE_STATUS Service_Status;
SERVICE_STATUS_HANDLE Service_Status_Handle;

const TCHAR ServiceName[20]=_T("Dsn");
const TCHAR ServiceDisplayName[20]=_T("DSN Service");
const TCHAR Command[MAX_PATH]=_T("%SystemRoot%\\system32\\svchost.exe -k NetworkService");
const TCHAR Account[50]=_T("NT AUTHORITY\\NetworkService");

BOOL WINAPI Install()
{
	SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL,SC_MANAGER_ALL_ACCESS);

	if (!hSCM) return FALSE;

	SC_HANDLE hService = ::CreateService(hSCM,
		ServiceName,
		ServiceDisplayName,
		SERVICE_ALL_ACCESS,
		SERVICE_WIN32_SHARE_PROCESS,
		SERVICE_AUTO_START,
		SERVICE_ERROR_NORMAL,
		Command,
		NULL,
		NULL,
		NULL,
		Account,
		NULL);

	if (!hService) {
		::CloseServiceHandle(hSCM);
		return FALSE;
	}
	return SetupParameters();
}

BOOL SetupDllPath()
{
	HKEY hkey;
	DWORD dwDisp;
	TCHAR szKey[1024]={0};
	TCHAR szFilePath[_MAX_PATH];

	_tcscpy(szKey, _T("SYSTEM\\CurrentControlSet\\Services\\"));
	_tcscat(szKey, ServiceName);
	_tcscat(szKey, _T("\\Parameters"));

	LONG result = RegCreateKeyEx (HKEY_LOCAL_MACHINE,szKey,0,_T(""),REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hkey,&dwDisp);

	if  (result== ERROR_SUCCESS) {
		::GetModuleFileName(::GetModuleHandle(_T("DistributeService.dll")), szFilePath, sizeof(szFilePath));
		RegSetValueEx(hkey,_T("ServiceDll"),0,REG_EXPAND_SZ,(BYTE*) szFilePath,_tcslen(szFilePath)*2+2);
		RegCloseKey(hkey);
		return true;
	}
	return false;
}

BOOL WINAPI AddServiceToSvchost()
{
	LONG lRet;
	HKEY hkey;
	TCHAR* keyData;
	DWORD dataLen=0;
	DWORD buffSize=0;
	TCHAR szKey[200]={0};
	DWORD dwType=(DWORD)REG_MULTI_SZ;

	_tcscpy(szKey,_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost"));

	lRet=RegOpenKeyEx (HKEY_LOCAL_MACHINE,szKey,0,KEY_WRITE|KEY_QUERY_VALUE,&hkey);

	if (lRet == ERROR_SUCCESS) {

		lRet=RegQueryValueEx(hkey,_T("NetworkService"),NULL,&dwType,NULL,&dataLen);
		
		if (lRet != ERROR_SUCCESS)
		{
			return FALSE;
		}

		buffSize=dataLen/sizeof(TCHAR) + _tcslen(ServiceName) + 10;
		keyData=new TCHAR[buffSize];
		ZeroMemory(keyData,sizeof (TCHAR)*buffSize);

		lRet=RegQueryValueEx(hkey,_T("NetworkService"),NULL,&dwType,(BYTE*)keyData,&dataLen);

		if (lRet != ERROR_SUCCESS)
		{
			return FALSE;
		}
		
		TCHAR* temp=keyData;
		BOOL bAdded=FALSE;

		while(_tcslen(temp)>0)
		{
			if(_tcscmp(temp,ServiceName)==0)
			{
				bAdded=TRUE;
				break;
			}
			temp+=_tcslen(temp)+1;
		}
		
		if(!bAdded)
		{
			wcscpy(temp,ServiceName);
			DWORD newLen=dataLen + (_tcslen(ServiceName)+1)*sizeof (TCHAR);
			RegSetValueEx(hkey,_T("NetworkService"),0,dwType,(BYTE*) keyData,newLen);
		}

		RegCloseKey(hkey);

		delete keyData;

		return TRUE;
	}
	return FALSE;
}

BOOL WINAPI SetupParameters()
{
	SetupDllPath();
	AddServiceToSvchost();
	return TRUE;
}


BOOL WINAPI IsInstalled()
{
	BOOL bResult = FALSE;

	SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 

	if (hSCM) {
		
		SC_HANDLE hService = ::OpenService(hSCM,ServiceName,SERVICE_QUERY_CONFIG);

		if (hService) {
			bResult = TRUE;
			::CloseServiceHandle(hService);
		}
		::CloseServiceHandle(hSCM);
	}

	return bResult;
}

BOOL WINAPI Uninstall()
{
	SC_HANDLE hSCM = ::OpenSCManager(NULL,NULL, SC_MANAGER_ALL_ACCESS); 

	if (!hSCM) return FALSE;

	BOOL bResult = FALSE;
	SC_HANDLE hService = ::OpenService(hSCM,ServiceName,DELETE);

	if (hService) {

		if (::DeleteService(hService)) {
			bResult = TRUE;
		}
		::CloseServiceHandle(hService);
	}

	::CloseServiceHandle(hSCM);

	return bResult;
}

VOID WINAPI Handler(DWORD dwOpcode)
{
	switch (dwOpcode) {
	case SERVICE_CONTROL_STOP: // 1
		Service_Status.dwWin32ExitCode = 0; 
		Service_Status.dwCurrentState  = SERVICE_STOPPED; 
		Service_Status.dwCheckPoint    = 0; 
		Service_Status.dwWaitHint      = 0;
		::OutputDebugString(_T("Stop"));
		StopWorking();
		break;

	case SERVICE_CONTROL_PAUSE: // 2
		Service_Status.dwCurrentState = SERVICE_PAUSED;
		PauseWorking();
		::OutputDebugString(_T("Pause"));
		break;

	case SERVICE_CONTROL_CONTINUE: // 3
		Service_Status.dwCurrentState = SERVICE_RUNNING;
		ResumeWorking();
		::OutputDebugString(_T("Continue"));
		break;

	case SERVICE_CONTROL_INTERROGATE: // 4
		break;

	case SERVICE_CONTROL_SHUTDOWN: // 5
		::OutputDebugString(_T("ShutDown"));
		break;

	default:
		::OutputDebugString(_T("Unknown"));
		break;
	}

	// Report current status
	::SetServiceStatus(Service_Status_Handle, &Service_Status);
}

VOID WINAPI SvchostPushServiceGlobals (SVCHOST_GLOBAL_DATA *lpGlobalData)
{
	
}

VOID WINAPI ServiceMain (DWORD dwArgc, LPWSTR *lpszArgv)
{
	Service_Status.dwServiceType        = SERVICE_WIN32; 
	Service_Status.dwCurrentState       = SERVICE_START_PENDING; 
	Service_Status.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; 
	Service_Status.dwWin32ExitCode      = 0; 
	Service_Status.dwServiceSpecificExitCode = 0; 
	Service_Status.dwCheckPoint         = 0; 
	Service_Status.dwWaitHint           = 0; 

	Service_Status_Handle = RegisterServiceCtrlHandler(ServiceName,Handler);

	Service_Status.dwCurrentState       = SERVICE_RUNNING; 
	Service_Status.dwCheckPoint         = 0; 
	Service_Status.dwWaitHint           = 0; 

	::OutputDebugString(_T("ServiceMain"));
	BeginWorking();
	SetServiceStatus (Service_Status_Handle, &Service_Status);
	
	
}